﻿/*  ------------------------------------------------------------------------
	 NQ Common Services Library
	 
	 Homepage: http://www.awzhome.de/
	 ------------------------------------------------------------------------
	 
	 The contents of this file are subject to the Mozilla Public License
	 Version 1.1 (the "License"); you may not use this file except in
	 compliance with the License. You may obtain a copy of the License at
	 http://www.mozilla.org/MPL/
	 
	 Software distributed under the License is distributed on an "AS IS"
	 basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	 License for the specific language governing rights and limitations
	 under the License.
	
	 The Original Code is code of NQ Common Services Library.

	 The Initial Developer of the Original Code is Andreas Weizel.
	 Portions created by the Initial Developer are
	 Copyright (C) 2006-2010 Andreas Weizel. All Rights Reserved.
	 
	 Contributor(s): (none)
	 
	 Alternatively, the contents of this file may be used under the terms
	 of the GNU General Public License Version 2.0 or later (the "GPL"),
	 or the GNU Lesser General Public License Version 2.1 or later (the
	 "LGPL"), in which case the provisions of the GPL or the LGPL are
	 applicable instead of those above. If you wish to allow use of your
	 version of this file only under the terms of the GPL or the LGPL and
	 not to allow others to use your version of this file under the MPL,
	 indicate your decision by deleting the provisions above and replace
	 them with the notice and other provisions required by the GPL or the
	 LGPL. If you do not delete the provisions above, a recipient may use
	 your version of this file under the terms of any of the MPL, the GPL
	 or the LGPL.
	 ------------------------------------------------------------------------
*/

using System;
using System.Collections.Generic;
using System.Text;

namespace AWZhome.NQ.CommonServices
{
	internal class JobReleaseList : IList<IRelease>
	{
		private List<IRelease> releaseList = new List<IRelease>();
		private NQUpdateService updateService;

		public JobReleaseList(NQUpdateService updateService)
		{
			this.updateService = updateService;
		}

		public JobReleaseList(NQUpdateService updateService, List<IRelease> newReleaseList)
		{
			this.updateService = updateService;
			this.releaseList = newReleaseList;
		}

		#region IList<INQRelease> Member

		public int IndexOf(IRelease item)
		{
			lock (updateService)
			{
				return releaseList.IndexOf(item);
			}
		}

		public void Insert(int index, IRelease item)
		{
			lock (updateService)
			{
				IInstallCheckResult checkResult = updateService.CheckInstallConditions(item.Conditions, true);
				if (checkResult.IsInstallable)
				{
					releaseList.Insert(index, item);
				}
				else
				{
					// Report reasons, why the release can't be installed.
					throw new UpdateCompatibilityException(
						"Release of " + item.ProductName + " can't be inserted into job list due to compatibility problems.",
						new IInstallCheckResult[] { checkResult });
				}
			}
		}

		public void RemoveAt(int index)
		{
			lock (updateService)
			{
				IRelease release = releaseList[index];
				if (release != null)
				{
					IInstallCheckResult[] checkResults = this.CheckCompatibilityOnRemove(release);
					if (checkResults == null)
					{
						// No compatibility issues are expected when removing the release from job list
						releaseList.RemoveAt(index);
					}
					else
					{
						// We can't remove the update, because this breaks other updates
						throw new UpdateCompatibilityException(
							"Release of " + release.ProductName + " can't be removed from job list, because this causes compatibility problems.",
							checkResults);
					}
				}
			}
		}

		public IRelease this[int index]
		{
			get
			{
				lock (updateService)
				{
					return releaseList[index];
				}
			}
			set
			{
				lock (updateService)
				{
					releaseList[index] = value;
				}
			}
		}

		#endregion

		#region ICollection<INQRelease> Member

		public void Add(IRelease item)
		{
			lock (updateService)
			{
				IInstallCheckResult checkResult = updateService.CheckInstallConditions(item.Conditions, true);
				if (checkResult.IsInstallable)
				{
					releaseList.Add(item);
				}
				else
				{
					// Report reasons, why the release can't be installed.
					throw new UpdateCompatibilityException(
						"Release of " + item.ProductName + " can't be added to job list due to compatibility problems.",
						new IInstallCheckResult[] { checkResult });
				}
			}
		}

		public void Clear()
		{
			lock (updateService)
			{
				releaseList.Clear();
			}
		}

		public bool Contains(IRelease item)
		{
			lock (updateService)
			{
				return releaseList.Contains(item);
			}
		}

		public void CopyTo(IRelease[] array, int arrayIndex)
		{
			lock (updateService)
			{
				releaseList.CopyTo(array, arrayIndex);
			}
		}

		public int Count
		{
			get
			{
				lock (updateService)
				{
					return releaseList.Count;
				}
			}
		}

		public bool IsReadOnly
		{
			get
			{
				lock (updateService)
				{
					return false;
				}
			}
		}

		public bool Remove(IRelease item)
		{
			lock (updateService)
			{
				IInstallCheckResult[] checkResults = this.CheckCompatibilityOnRemove(item);
				if (checkResults == null)
				{
					// No compatibility issues are expected when removing the release from job list
					return releaseList.Remove(item);
				}
				else
				{
					// We can't remove the update, because this breaks other updates
					throw new UpdateCompatibilityException(
						"Release of " + item.ProductName + " can't be removed from job list, because this causes compatibility problems.",
						checkResults);
				}
			}
		}

		#endregion

		#region IEnumerable<INQRelease> Member

		public IEnumerator<IRelease> GetEnumerator()
		{
			lock (updateService)
			{
				return releaseList.GetEnumerator();
			}
		}

		#endregion

		#region IEnumerable Member

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			lock (updateService)
			{
				return releaseList.GetEnumerator();
			}
		}

		#endregion

		#region Private methods

		/// <summary>
		/// Checks, whether some updates in the job list would fail, when a certain release was removed from it.
		/// </summary>
		/// <param name="release">Release to remove.</param>
		/// <returns>
		/// List of check result objects for every release, that would fail after removing <paramref name="release"/>,
		/// or <c>null</c>, if no compatibility issues should be expected.
		/// </returns>
		private IInstallCheckResult[] CheckCompatibilityOnRemove(IRelease release)
		{
			List<IInstallCheckResult> checkResults = new List<IInstallCheckResult>();

			// Temporarily drop the release from job list
			int releaseIndex = releaseList.IndexOf(release);
			releaseList.Remove(release);

			// Enumerate all releases
			foreach (IRelease relitem in releaseList)
			{
				IInstallCheckResult releaseCheck = updateService.CheckInstallConditions(relitem.Conditions, true);
				if (!releaseCheck.IsInstallable)
				{
					// This update has compatibility issues
					checkResults.Add(releaseCheck);
				}
			}

			// Insert deleted release back to job list
			releaseList.Insert(releaseIndex, release);

			if (checkResults.Count > 0)
			{
				IInstallCheckResult[] result = new IInstallCheckResult[checkResults.Count];
				checkResults.CopyTo(result);
				return result;
			}
			else
			{
				return null;
			}
		}

		#endregion
	}
}
